﻿using System;

namespace SoftwareConsulting.BI11.NumericalMethods.Optimization
{
    /// <summary>
    /// Класс абстрактного контроллера хромосом
    /// </summary>
    public abstract class ChromosomeController
    {        
        private int _populationSize = 100;     
        private double _rateOfMutation = 0.1;        
        private double _rateOfCrossover = 0.1;        
        private readonly Random _generator;

        /// Constructor method.
        public ChromosomeController() : base()
        {
            _generator = new Random();
        }

        /// <summary>
        /// Конструктор класса
        /// </summary>
        /// <param name="populationSize">размер популяции</param>
        /// <param name="rateOfMutation">частота мутации</param>
        /// <param name="rateOfCrossover">частота скрещивания</param>
        public ChromosomeController(int populationSize, double rateOfMutation, double rateOfCrossover):
            this()
        {
            _populationSize = populationSize;
            _rateOfMutation = rateOfMutation;
            _rateOfCrossover = rateOfCrossover;
        }

        /// <summary>
        /// Добавляет клон указанного объекта
        /// </summary>
        /// <param name="originalObject"></param>
        public abstract void AddCloneOf(object originalObject);

        /// <summary>
        /// Добавляет результат скрещивания указанных объектов
        /// </summary>
        /// <param name="fatherObject"></param>
        /// <param name="motherObject"></param>
        public abstract void AddCrossoversOf(object fatherObject, object motherObject);

        /// <summary>
        /// Добавляет результат мутации указанного объекта
        /// </summary>
        /// <param name="originalObject"></param>
        public abstract void AddMutationOf(Object originalObject);

        /// <summary>
        /// Добавляет случайную хромосому
        /// </summary>
        public abstract void AddRandomChromosome();

        /// <summary>
        /// Возвращает текущий размер популяции
        /// </summary>
        public abstract int CurrentPopulationSize { get; }

        /// <summary>
        /// Возвращает/устанавливает желаемый размер популяции
        /// </summary>
        public int DesiredPopulationSize
        {
            get 
            { 
                return _populationSize; 
            }
            set 
            {
                _populationSize = value; 
            }
        }

        /// <summary>
        /// Возвращает указанную особь
        /// </summary>
        /// <param name="individualIndex"></param>
        /// <returns></returns>
        public abstract object GetIndividualAt(int individualIndex);

        /// <summary>
        /// Возвращает флаг полностью заселенной популяции
        /// </summary>
        public bool IsFullyPopulated
        {
            get 
            { 
                return this.CurrentPopulationSize >= _populationSize; 
            }
        }

        /// <summary>
        /// Возвращает следующее случайное вещественное число
        /// </summary>
        /// <returns></returns>
        public double GetNextRandomDouble()
        {
            return _generator.NextDouble();
        }

        /// <summary>
        /// Обрабатывает два объекта
        /// </summary>
        /// <param name="fatherObject"></param>
        /// <param name="motherObject"></param>
        public void Process(object fatherObject, object motherObject)
        {
            double rand = _generator.NextDouble();
            if (rand < _rateOfCrossover)
            {
                AddCrossoversOf(fatherObject, motherObject);
                return;
            }
            if (rand < _rateOfCrossover + _rateOfMutation)
            {
                AddMutationOf(fatherObject);
                AddMutationOf(motherObject);
                return;
            }
            AddCloneOf(fatherObject);
            AddCloneOf(motherObject);
        }

        /// <summary>
        /// Создает популяции из случайных хромосом
        /// </summary>
        public void RandomizePopulation()
        {
            Reset();
            while (!this.IsFullyPopulated)
                AddRandomChromosome();
        }

        /// <summary>
        /// Сбрасывает популяцию
        /// </summary>
        public abstract void Reset();

        /// <summary>
        /// Возвращает/устанавливает частоту скрещивания
        /// </summary>
        public double RateOfCrossover
        {
            get
            {
                return _rateOfCrossover;
            }
            set 
            { 
                _rateOfCrossover = value; 
            }
        }

        /// <summary>
        /// Возвращает/устанавливает частоту мутаций
        /// </summary>
        public double RateOfMutation
        {
            get
            {
                return _rateOfMutation;
            }
            set 
            { 
                _rateOfMutation = value; 
            }
        }
    }
}
